/****************************************************************
 * Copyright PurpleWisteria. All Rights Reserved.
 ****************************************************************/

"use strict";

/**
 * WebSocket客户端
 */
class NeptWebSocket {
    /**
     * 构造
     * @param {string} ip 服务器IP地址
     * @param {number} port 服务器端口号
     * @param {number} connectionTimeout 连接超时毫秒数（若为正数，则超时将重连）
     * @param {function} onReceive 接收消息的函数
     * @param {string} urlParam 链接参数（可为null或空）
     * @param {string} path 链接路径（非必填）
     */
    constructor(ip, port, connectionTimeout, onReceive, urlParam, path = null) {
        /**
         * WebSocket对象
         */
        let m_ClientWebSocket = null;

        /**
         * 输入参数是否为null或空
         * @param {*} inParam 入参
         * @returns 是否为null或空
         */
        const isNullOrEmpty = function(inParam) {
            return inParam == undefined || inParam == null || inParam == "";
        }

        /**
         * 服务器Url
         */
        let m_ServerUrl = "ws://" + ip + ":" + port + "/";

        // 尝试添加路径
        if (!isNullOrEmpty(path)) {
            m_ServerUrl += path;
        }

        // 尝试添加链接参数
        if (!isNullOrEmpty(urlParam)) {
            m_ServerUrl += "?" + urlParam;
        }

        /**
         * 连接超时毫秒数（超时将重连）
         */
        const m_ConnectionTimeout = connectionTimeout;

        /**
         * 接收消息的函数
         */
        const m_OnReceive = onReceive;

        /**
         * 重连定时器
         */
        let m_ReconnectionTimer = null;

        /**
         * 最后一次收到消息的时间（毫秒）
         */
        let m_LastReceivedTime = 0;

        /**
         * 监视重连的间隔时间（毫秒）
         */
        const m_MonitorReconnectionInterval = 3000;

        /**
         * 对象自身
         */
        const m_Self = this;

        /**
         * 响应事件：打开
         */
        const onOpen = function() {
            // console.log("[NeptWebSocket][onOpen]server url: " + m_ServerUrl);
        }

        /**
         * 响应事件：关闭
         */
        const onClose = function() {
            // console.log("[NeptWebSocket][onClose]server url: " + m_ServerUrl);
            m_LastReceivedTime = 0;
        }

        /**
         * 响应事件：错误
         */
        const onError = function() {
            // console.log("[NeptWebSocket][onError]server url: " + m_ServerUrl);
            m_LastReceivedTime = 0;
        }

        /**
         * 响应事件：收到消息
         * @param {*} message 收到的消息
         */
        const onMessage = function(message) {
            m_LastReceivedTime = Date.now();
            if (isNullOrEmpty(message)) {
                return;
            }

            try {
                m_OnReceive(message.data);
            }
            catch (e) {
                // console.log("[NeptWebSocket][onMessage]exception: " + e);
            }
        }

        /**
         * 监视重连
         * @returns void
         */
        const monitorReconnection = function() {
            if (m_ConnectionTimeout == null || isNaN(m_ConnectionTimeout) || m_ConnectionTimeout <= 0) {
                return;
            }

            if (m_ReconnectionTimer != null) {
                return;
            }

            // console.log("[NeptWebSocket][monitorReconnection]connection timeout: " + m_ConnectionTimeout + ", server url: " + m_ServerUrl);
            m_ReconnectionTimer = setInterval(function() {
                if ((Date.now() - m_LastReceivedTime) <= m_ConnectionTimeout) {
                    return;
                }

                if ((m_ClientWebSocket == null) || (m_ClientWebSocket.readyState !== WebSocket.CLOSED)) {
                    return;
                }

                try {
                    m_ClientWebSocket.close();
                }
                catch (e) {
                    // console.log("[NeptWebSocket][monitorReconnection]exception: " + e);
                }

                m_ClientWebSocket = null;
                m_Self.tryCreate();
            }, m_MonitorReconnectionInterval);
        }

        /**
         * 尝试创建WebSocket
         * @returns 是否创建成功
         */
        this.tryCreate = function() {
            const FUNCTION = "function";
            if (typeof(WebSocket) !== FUNCTION) {
                alert("当前环境不支持WebSocket");
                return false;
            }

            if (m_ClientWebSocket != null) {
                return true;
            }

            try {
                m_ClientWebSocket = new WebSocket(m_ServerUrl);
            }
            catch (e) {
                // console.log("[NeptWebSocket][tryCreate]exception: " + e);
                return false;
            }

            m_ClientWebSocket.onopen = onOpen;
            m_ClientWebSocket.onclose = onClose;
            m_ClientWebSocket.onerror = onError;
            if ((m_OnReceive != null) && (typeof(m_OnReceive) === FUNCTION)) {
                m_ClientWebSocket.onmessage = onMessage;
                monitorReconnection();
            }
            else {
                // console.warn("[NeptWebSocket][tryCreate]no receive function. server url: " + m_ServerUrl);
            }

            return true;
        }

        /**
         * 获取连接状态
         * @returns 连接状态
         */
        this.getReadyState = function() {
            if (m_ClientWebSocket == null) {
                return WebSocket.CLOSED;
            }

            return m_ClientWebSocket.readyState;
        }

        /**
         * 发送
         * @param {*} message 发送的消息
         * @returns void
         */
        this.send = function(message) {
            if (m_ClientWebSocket == null || m_ClientWebSocket.readyState !== WebSocket.OPEN) {
                return;
            }

            try {
                m_ClientWebSocket.send(message);
            }
            catch (e) {
                // console.log("[NeptWebSocket][send]exception: " + e);
            }
        }

        /**
         * 关闭
         * @returns void
         */
        this.close = function() {
            // console.log("[NeptWebSocket][close]server url: " + m_ServerUrl);
            if (m_ClientWebSocket == null) {
                return;
            }

            try {
                m_ClientWebSocket.close();
            }
            catch (e) {
                // console.log("[NeptWebSocket][close]exception: " + e);
            }

            m_ClientWebSocket = null;
            if (m_ReconnectionTimer != null) {
                clearInterval(m_ReconnectionTimer);
                m_ReconnectionTimer = null;
            }
        }
    }
}

// export { NeptWebSocket };
